/*

  MMetaverseSurface

  Copyright (c) 2009 Mary Jane Soft - Marlon J. Manrique
	
  http://www.maryjanesoft.com
  http://www.marlonj.com

  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 2
  of the License, or (at your option) any later version.
 
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
 
  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

  $Id$
	
*/

using System.Collections;
using Nwc.XmlRpc;

namespace mjs.mmetaverse.surface
{
	/// <summary>
	///  Information about the object to use inside the MMetaverseSurface.
	///  The information for each object is the fiducial id, and the 
	///  XML-RPC channel identifier.
	/// </summary>
	public class RemoteObject
	{
		/// <summary>
		/// Move Request identifier.
		/// </summary>
		private const int REQUEST_MOVE = 1;

		/// <summary>
		/// Rotate Request identifier.
		/// </summary>
		private const int REQUEST_ROTATE = 2;

		/// <summary>
		/// Fiducial asigned to the object.
		/// </summary>
		private int fiducialID;

		/// <summary>
		/// XML-RPC channel assigned by the region.
		/// </summary>
		private string channelID;

		/// <summary>
		/// Server URL to send the XML-RPC request.
		/// </summary>
		private string serverURL;

		/// <summary>
		/// Current X location.
		/// </summary>
		private float x;
		
		/// <summary>
		/// Current Y location.
		/// </summary>
		private float y;

		/// <summary>
		/// Current Z location.
		/// </summary>
		private float z;

		/// <summary>
		/// Current angle.
		/// </summary>
		private float angle;

		/// <summary>
		/// Create a new information from a Remote Object.
		/// </summary>
		/// <param name="fiducialID">
		/// The fiducial id use in the reacTIVision table. <see cref="System.Int32"/>
		/// </param>
		/// <param name="channelID">
		/// The XML-RPC channel identifier. <see cref="System.String"/>
		/// </param>
		/// <param name="serverURL">
		/// Server URL to send the XML-RPC request. <see cref="System.String"/>
		/// </param>
		public RemoteObject(int fiducialID, string channelID, string serverURL)
		{
			this.fiducialID = fiducialID;
			this.channelID = channelID;
			this.serverURL = serverURL;
		}

		/// <summary>
		/// Return the fiducial identifier use in the reacTIVision.
		/// </summary>
		/// <returns>
		/// The fiducial identifier identifier. <see cref="System.Int32"/>
		/// </returns>
		public int getFiducialID() 
		{
			return fiducialID;
		}

		/// <summary>
		/// Return the channel id use to send XML-RPC requests.
		/// </summary>
		/// <returns>
		/// The channel id. <see cref="System.String"/>
		/// </returns>
		public string getChannelID() 
		{
			return channelID;
		}

		/// <summary>
		/// Move the object to the location specified inside the region.
		/// </summary>
		/// <param name="x">
		/// The x coordinate inside the region. <see cref="System.Single"/>
		/// </param>
		/// <param name="y">
		/// The y coordinate inside the region. <see cref="System.Single"/>
		/// </param>
		/// <param name="z">
		/// The y coordinate inside the region. <see cref="System.Single"/>
		/// </param>
		public void move(float x, float y, float z)
		{
			// Check if some values changed and request move 
			if(this.x != x || this.y != y || this.z != z)
			{
				// Send a string with the location info to the 
				// Object inside the simulator
				// Use the vector representation 
				string data = "<" + x + "," + y + "," + z + ">";
				sendRequest(REQUEST_MOVE,data);
			}

			// Update the object location
			this.x = x;
			this.y = y;
			this.z = z;

		}

		/// <summary>
		/// Send the rotate request.
		/// </summary>		
		/// <param name="angle">
		/// The angle in radians to rotate. <see cref="System.Single"/>
		/// </param>
		public void rotate(float angle)
		{
			// Check if the object is not already rotate 
			// and send rotate request 
			if(this.angle != angle)
			{
				// Send a string with the rotation info to the 
				// Object inside the simulator
				string data = "" + angle;
				sendRequest(REQUEST_ROTATE,data);
			}

			// Update angle 
			this.angle = angle;
		}

		/// <summary>
		/// Send the request to the remote object using XML-RPC.
		/// </summary>		
		/// <param name="requestID">
		/// Request identifier. <see cref="System.Int32"/>
		/// </param>		
		/// <param name="data">
		/// Data to send to the object. <see cref="System.String"/>
		/// </param>		
		private void sendRequest(int requestID, string data)
		{
			// Set arguments 
			Hashtable args = new Hashtable();
			args.Add("Channel",channelID); 
			args.Add("IntValue",requestID); 
			args.Add("StringValue",data); 

			// Send Request 
			XmlRpcRequest request = new XmlRpcRequest();
			request.MethodName = "llRemoteData";
			request.Params.Add(args);
			request.Invoke(serverURL);
		}
	}
}
